package com.lemurian.bankdata.interceptor;

import java.io.Serializable;
import java.util.Date;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.SessionMap;

import com.lemurian.bankdata.lite.authentication.BankDataPrincipal;
import com.lemurian.bankdata.lite.logger.BankDataLogger;
import com.lemurian.bankdata.lite.utils.GeneralConstant;
import com.lemurian.bankdata.lite.utils.GlobalFunction;
import com.lemurian.entity.Menu;
import com.lemurian.entity.User;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

public class AuthenticationInterceptor extends AbstractInterceptor implements Serializable {

	private static final long serialVersionUID = 1L;
    private static final String authenticationRequiredResult = "authentication_required";
    private static final String privilegeRequiredResult = "privilege_required";
    private static final String userLoggedOnAtAnotherDevice = "info_another_login";
    private BankDataLogger log = BankDataLogger.getLogger(AuthenticationInterceptor.class.getSimpleName());

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
    	
        Map<String, Object> session = invocation.getInvocationContext().getSession();
        HttpServletRequest request = ServletActionContext.getRequest();
        log.sInfo(":: INTERCEPTOR ACTIVATED BEFORE INVOKE ACTION : %s", request.getRequestURI());
        
    	BankDataPrincipal principal = null;
        String customMessage = null;
        String customWarning = null;
        String customError = null;
        
        try {
        	
            principal = (BankDataPrincipal) session.get(GeneralConstant.USER_PRINCIPAL);
            customMessage = (String) session.get(GeneralConstant.CUSTOM_ACTION_MESSAGE);
            customError = (String) session.get(GeneralConstant.CUSTOM_ACTION_ERROR);
            
        } catch (Throwable ex) {
        	
            log.sInfo("FAILED TO FETCH BANKDATA BACKOFFICE PRINCIPAL: %s", ex.getMessage());
            
            ((SessionMap) session).invalidate();
            
            request.getSession(true);
            
            if(customMessage != null) {
            	session.put(GeneralConstant.CUSTOM_ACTION_MESSAGE, customMessage);
            }
            
            if(customWarning != null) {
            	session.put(GeneralConstant.CUSTOM_ACTION_WARNING, customMessage);
            }
                
            if(customError != null) {
            	session.put(GeneralConstant.CUSTOM_ACTION_ERROR, customError);
            }
                
            return authenticationRequiredResult;
        }
        
        if (principal == null) {
        	
            log.warn(":: PRINCIPAL IS NULL");
            ((SessionMap) session).invalidate();
            request.getSession(true);
            
            if(customMessage != null) {
            	session.put(GeneralConstant.CUSTOM_ACTION_MESSAGE, customMessage);
            }
            
            if(customWarning != null) {
            	session.put(GeneralConstant.CUSTOM_ACTION_WARNING, customMessage);
            }
                
            if(customError != null) {
            	session.put(GeneralConstant.CUSTOM_ACTION_ERROR, customError);
            }
                
            return authenticationRequiredResult;
            
        } else {
        	
            User user = principal.getUser();
            log.sInfo(":: USER SESSIONID [%s]", user.getSessionId());
            log.sInfo(":: REQUEST SESSIONID [%s]", request.getSession().getId());

            if (user.getSessionId() != null && user.getSessionValidTime() != null && user.getSessionId().equals(request.getSession().getId())
                    && (user.getSessionValidTime()).after(new Date())) {
            	
                log.sInfo(":: CUSTOMER SESSION ID IS VALID");

                //set active menu
                try {
                	
                    Menu menu = GlobalFunction.getActiveMenu(principal, invocation.getProxy().getActionName());
                    if(menu != null) {
                    	
                    	log.sInfo(":: ACTIVE MENU : %s", menu.getName());
                        session.put(GeneralConstant.ACTIVE_MENU, menu);
                        
                    } else {
                    	
                        log.sInfo(":: FAILED TO SET ACTIVE MENU [%s]. IT MEANS USER HAVE NO PRIVILEGE.",
                        invocation.getProxy().getActionName());
                        return privilegeRequiredResult;
                        
                    }
                    
                } catch (Throwable th) {
                    log.sInfo(":: FAILED TO SET ACTIVE MENU DUE TO ERROR : %s. ", th.getMessage());
                }

                return invocation.invoke();

            } else {
                log.sInfo(":: USER HAS BEEN LOGGED ON AT ANOTHER DEVICE");
                session.clear();
                
                if (session instanceof SessionMap) {
                    try {
                        ((SessionMap) session).invalidate();
                    } catch (IllegalStateException ise) {
                        String msg = "'FrontAction.logoff' caught an " + "IllegalStateException, possibly because the session " + "has already been invalidated or timed out.";
                        log.sInfo(msg);
                    }
                }
                
                return userLoggedOnAtAnotherDevice;
            }
        }
    }

    public boolean validateCustomer(User user, String sessionId) {
        try {
            if (user.getSessionValidTime().before(new Date())) {
                log.sInfo(":: SESSION VALID TIME IS ALREADY EXPIRED");
            }
            if (user.getSessionId() != null && user.getSessionValidTime() != null && user.getSessionId().equals(sessionId) && (user.getSessionValidTime()).after(new Date())) {
                return true;
            } else {
                log.sInfo(":: CUSTOMER SESSION ID IS NULL");
                return false;
            }
        } catch (Throwable e) {
            log.sInfo(":: ERROR ON SESSION");
            return false;
        }
    }

    @Override
    public void destroy() {
        super.destroy();
    }

    @Override
    public void init() {
        super.init();
    }
}